﻿#region File Header
//-----------------------------------------------------------------------------
// Bricks' Bane
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SibLib.Containers;
using SibLib.Entities;
using SibLib.Render;
using SibLib.Render.Primitives3D;

namespace BricksBane.Entities
{
    /// <summary>
    /// A lot of bricks put together.
    /// </summary>
    sealed class Wall : GameplayObject, ICollideable2D
    {
        #region Members
        private AutoPool<Brick> m_Bricks;

        private static readonly Vector2 BASE_POSITION = new Vector2(128 - 8, 72);       // Safe area
        private static readonly Vector2 AREA_SIZE = new Vector2(1280 - 368, 720 - 144);     // = 912, 576
        private static readonly Vector2 BRICK_SIZE_DEFAULT = new Vector2(48, 24);

        private Rectangle m_BoundingBox;

        private GeometricPrimitive m_PrimitiveHoriz;
        private GeometricPrimitive m_PrimitiveVert;
        private Matrix[] m_MatrixLimits;

        public bool IsShieldEnabled
        {
            get;
            private set;
        }
        private float m_ShieldTimer;
        private int m_ShieldHP;
        #endregion

        #region Properties
        public Vector2 BrickSize
        {
            get;
            set;
        }

        public int BonusPercent
        {
            get;
            set;
        }

        public Color Color
        {
            get;
            set;
        }
        #endregion

        public Wall()
        {
            m_Bricks = new AutoPool<Brick>(256);

            BrickSize = BRICK_SIZE_DEFAULT;
            BonusPercent = 15;
            Color = Color.White;
        }

        public override void Initialize()
        {
            base.Initialize();

            Vector2 halfSize = AREA_SIZE / 2.0f;
            m_MatrixLimits[0] = Matrix.CreateTranslation(new Vector3(BASE_POSITION.X - 8.0f, BASE_POSITION.Y + halfSize.Y, 0.0f));
            m_MatrixLimits[1] = Matrix.CreateTranslation(new Vector3(BASE_POSITION.X + AREA_SIZE.X + 8.0f, BASE_POSITION.Y + halfSize.Y, 0.0f));
            m_MatrixLimits[2] = Matrix.CreateRotationZ(MathHelper.PiOver2) * Matrix.CreateTranslation(new Vector3(BASE_POSITION.X + halfSize.X, BASE_POSITION.Y - 8.0f, 0.0f));
            m_MatrixLimits[3] = Matrix.CreateRotationZ(MathHelper.PiOver2) * Matrix.CreateTranslation(new Vector3(BASE_POSITION.X + halfSize.X, BASE_POSITION.Y + AREA_SIZE.Y - 8.0f, 0.0f));

            m_Bricks.ProcessAdds();
            foreach (Brick brick in m_Bricks)
                brick.Initialize();

            m_BoundingBox = new Rectangle((int)BASE_POSITION.X, (int)BASE_POSITION.Y, (int)AREA_SIZE.X, (int)AREA_SIZE.Y);
            IsShieldEnabled = false;
            m_ShieldTimer = 0.0f;
            m_ShieldHP = 0;
        }

        protected override void LoadContent()
        {
            base.LoadContent();

            GraphicsDevice device = GameplayScreen.Instance.GraphicsDevice;
            m_MatrixLimits = new Matrix[4];
            m_PrimitiveVert = new CylinderPrimitive(device, AREA_SIZE.Y, 16.0f, 8);
            m_PrimitiveHoriz = new CylinderPrimitive(device, AREA_SIZE.X + 32.0f, 16.0f, 8);
        }

        public void Generate(List<Drop> dropPool)
        {
            for (int y = 0; y != 8; y++)
            {
                for (int x = 0; x != 16 - (y & 1); x++)
                {
                    Brick brick = m_Bricks.AddNewItem();
                    SetupBrick(ref brick, x * 4 + (y & 1) * 2, y * 2);      // * 4 = (64 / 16), * 2 = (32 / 16) = BrickSize / GridSize
                    brick.Color = new Color(SibLib.RandomMath.RandomVector3(0.2f, 1.0f));                    
                    brick.HitPoints = 1;
                }
            }
        }

        public Brick GetNewBrick()
        {
            return m_Bricks.AddNewItem();
        }

        public Rectangle GetBoundingBox()
        {
            return m_BoundingBox;
        }

        /// <summary>
        /// Setup brick position and size, and add brick to wall's owned bricks.
        /// </summary>
        /// <param name="brick"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void SetupBrick(ref Brick brick, float x, float y)
        {
            brick.Position = BASE_POSITION + new Vector2((x * 8) + (BrickSize.X / 2.0f), (y * 8) + (BrickSize.Y / 2.0f));
            brick.Size = BrickSize;
            brick.IsActive = true;
        }

        public void ActivateShieldHit()
        {
            IsShieldEnabled = true;
            if (m_ShieldHP <= 0)
                m_ShieldHP = 3;     // TODO: tuning
            else
                m_ShieldHP += 3;
            m_ShieldTimer = 0.0f;
        }

        public void ActivateShieldTime()
        {
            IsShieldEnabled = true;
            m_ShieldHP = -1;
            if (m_ShieldTimer <= 0.0f)
                m_ShieldTimer = 10.0f;  // TODO: tuning
            else
                m_ShieldTimer += 10.0f; // TODO: tuning
        }

        public override void Update(float timeFactor)
        {
            m_Bricks.ProcessAdds();
            foreach (Brick brick in m_Bricks)
            {
                brick.Update(timeFactor);
                if (!brick.IsActive)
                    m_Bricks.Remove(brick);
            }
            m_Bricks.ProcessRemoves();
            if (m_Bricks.Count == 0)
                GameplayScreen.Instance.OnWallDestroyed();

            if (m_ShieldTimer > 0.0f)
            {
                m_ShieldTimer -= timeFactor;
                if (m_ShieldTimer <= 0.0f)
                    IsShieldEnabled = false;
            }
        }

        public void OnBallHitShield(Ball ball)
        {
            if (m_ShieldHP > 0)
            {
                m_ShieldHP--;
                if (m_ShieldHP == 0)
                    IsShieldEnabled = false;
            }
        }

        public override void Draw(float timeFactor)
        {
            SceneInfo info = GameplayScreen.Instance.SceneInfo;
            m_PrimitiveVert.Draw(m_MatrixLimits[0], info.ViewMatrix, info.ProjectionMatrix, Color);
            m_PrimitiveVert.Draw(m_MatrixLimits[1], info.ViewMatrix, info.ProjectionMatrix, Color);
            m_PrimitiveHoriz.Draw(m_MatrixLimits[2], info.ViewMatrix, info.ProjectionMatrix, Color);

            if (IsShieldEnabled)
                m_PrimitiveHoriz.Draw(m_MatrixLimits[3], info.ViewMatrix, info.ProjectionMatrix, new Color(Color, 150));

            foreach (Brick brick in m_Bricks)
            {
                brick.Draw(timeFactor);
            }
        }

        #region Enumerator

        public List<Brick>.Enumerator GetEnumerator()
        {
            return m_Bricks.GetEnumerator();
        }
        #endregion
    }
}
